package com.xiao.spring.ioc.register;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

/**
 * 动态生成bean
 * 
 * @author xiao.he
 *
 */
@Component
public class RegisterBeanConfig implements BeanFactoryPostProcessor {

	private static Class<?> makeClass;

	private static String[] makeClassNames;

	static {
		// 初始化参数
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			ClassPool pool = ClassPool.getDefault();
			CtClass ctClass = pool.get(makeClass.getName());
			for (String makeClassName : makeClassNames) {
				String beanName = getMakeClassName(ctClass.getSimpleName(), makeClassName);
				if (beanFactory.containsBean(beanName)) {
					continue;
				}
				CtClass newCtClass = pool.makeClass(ctClass.getClassFile(), false);
				newCtClass.setName(beanName);
				GenericBeanDefinition gbd = new GenericBeanDefinition();
				gbd.setBeanClass(newCtClass.toClass());
				gbd.setSynthetic(true);
				((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(beanName, gbd);
			}
		} catch (NotFoundException e) {
			e.printStackTrace();
		} catch (CannotCompileException e) {
			e.printStackTrace();
		}
	}

	private String getMakeClassName(String className, String suffix) {
		return new StringBuilder(className).append("$").append(suffix).toString();
	}

	public void updateAnnotation(Class clz, Class annoClz, String annoVal) throws NoSuchFieldException,
			SecurityException, IllegalArgumentException, IllegalAccessException {
		Object annotation = clz.getAnnotation(annoClz);
		if (annotation != null) {
			InvocationHandler ih = Proxy.getInvocationHandler(annotation);
			Field memberValuesField = ih.getClass().getDeclaredField("memberValues");
			memberValuesField.setAccessible(true);
			Map memberValues = (Map) memberValuesField.get(ih);
			memberValues.put("value", annoVal);
		}
	}

}
